﻿#include "OiPCH.hpp"
#include "Camera/Optex/OptexSensor.hpp"

namespace Oi
{
    namespace PLScannerCore
    {
        class SensorAcquireImpl;
        class AcquireProfileTask : public QThread
        {
        public:
            void setCallback(AcquireProfileCallback callback, void* data);
            void setParams(double vel, double form = 0.0, double end = 0.0);

        public:
            void run();
            void quit();
            void start();

        public:
            SensorAcquireImpl* _impl;

        public:
            AcquireProfileCallback _callback = nullptr;
            void* _data;

        public:
            double _from;
            double _end;
            double _vel;

        public:
            Base::Barrier _waiter;
            QMutex _mutex;
            bool _quit;

        public:
            OiProfile _profile;
            bool _dir;
            bool _success;

        public:
            int _timeTick1 = 0;
            int _timeTick2 = 0;
        };

        class AcquireValueTask : public QThread
        {
        public:
            void setCallback(AcquireValueCallback callback, void* data);
            void setParams(double pos = 0.0);

        public:
            void run();
            void quit();
            void start();

        public:
            SensorAcquireImpl* _impl;

        public:
            AcquireValueCallback _callback = nullptr;
            void* _data;

        public:
            double _pos;

        public:
            Base::Barrier _waiter;
            QMutex _mutex;
            bool _quit;

        public:
            double _value;
            bool _success;
            int _loopTime;
        };

        class SensorAcquireImpl : public Impl<SensorAcquire>
        {
        public:
            void init();
            void exit();

        public:
            AcquireProfileTask profileTask;
            AcquireValueTask valueTask;

        public:
            Device* _sensor;
        };

        void AcquireProfileTask::setCallback(AcquireProfileCallback callback, void* data)
        {
            QMutexLocker locker(&_mutex);
            _callback = callback;
            _data = data;
        }

        void AcquireProfileTask::setParams(double vel, double form /*= -1*/, double end /*= -1*/)
        {
            QMutexLocker locker(&_mutex);
            _vel = vel;
            _from = form;
            _end = end;
        }

        void AcquireProfileTask::run()
        {
            //电机控制，注意 _quit = true 及时中断退出 传感器连接超时退出

            bool dir = false;

            if (!PLScanner::instance()->simulation)
            {
                if (!Motor::instance()->isReady())
                {
                    OiWarning() << tr("轴状态不正确");
                    return;
                }

                if ((_impl->_sensor->getStatus() & Device::DS_Linked ) == 0)
                {
                    OiWarning() << tr("传感器未通信成功");
                    return;
                }

//                OiShowMessage(tr("正在等待轴回起始点"));

                if (PLScanner::instance()->debugging)
                {
                    _timeTick1 = QDateTime::currentDateTime().toMSecsSinceEpoch();
                    OiWarning() << "Profile loop Interval:" << _timeTick1 - _timeTick2;
                    _timeTick2 = _timeTick1;
                }

                int timerCounter = 0;
// 
//                 while (!Motor::instance()->loopModeReady())
//                 {
//                     if (_quit || !Environment::_startTask)
//                     {
//                         return;
//                     }
// 
//                     if (timerCounter > 100)
//                     {
//                         OiShowMessage(tr("等待轴回起始点超时"));
// 
//                         return;
//                     }
// 
//                     timerCounter++;
// 
//                     QThread::msleep(100);
//                 }

                _impl->_sensor->startCapture();

                if (PLScanner::instance()->debugging)
                {
                    _timeTick1 = QDateTime::currentDateTime().toMSecsSinceEpoch();
                    _timeTick2 = _timeTick1;
                }

                Motor::instance()->loopRun(_vel, _from, _end);

                QThread::msleep(1000);

                dir = Motor::instance()->axisMoveForward();

               // OiWarning() << "axisMoveForward:" << dir << "acquireDir:" << PLScanner::instance()->acquireDir;

                OiShowMessage(tr("正在等待轴运动"));

                timerCounter = 0;
                
                while (!Motor::instance()->loopModeReady())
                {
                    if (_quit || !Environment::_startTask)
                    {
                        return;
                    }

                    if (timerCounter > 6000)
                    {
                        OiWarning() << (tr("等待轴运动过程超时"));
                        return;
                    }

                    timerCounter++;

                    QThread::msleep(10);
                }

                if (PLScanner::instance()->debugging)
                {
                    _timeTick1 = QDateTime::currentDateTime().toMSecsSinceEpoch();
                    OiWarning() << "Profile loop Move:" << _timeTick1 - _timeTick2;
                    _timeTick2 = _timeTick1;
                }
            } 

            //bool dir = Motor::instance()->axisMoveForward();

            //OiWarning() << "axisMoveForward:" << dir << "acquireDir:" << PLScanner::instance()->acquireDir;
            _impl->_sensor->stopCapture(400);
            if (_from == 0 && _end == 0)
            {
                _impl->_sensor->stopCapture(1000);
            }
            else
            {
                _impl->_sensor->stopCapture(300 + (_end - _from));
            }

            if (PLScanner::instance()->debugging)
            {
                _timeTick1 = QDateTime::currentDateTime().toMSecsSinceEpoch();
                OiWarning() << "Profile loop StopCapture:" << _timeTick1 - _timeTick2;
                _timeTick2 = _timeTick1;
            }

            if (1)
            {
                OiProfile nProfile;

                std::vector<double> sp;
                QVariantMap infos;

                if (_impl->_sensor->getProifile(sp, infos))
                {
                    for (int i = 0; i < sp.size(); i++)
                    {
                        if (dir == PLScanner::instance()->acquireDir )
                        {
                            if (sp[i] > 50.0 || sp[i] <= 0.0)
                            {
                                nProfile.push_back(QPointF(i * PLScanner::instance()->resolution, 0.0));
                            }
                            else
                            {
                                nProfile.push_back(QPointF(i * PLScanner::instance()->resolution, sp[i] + PLScanner::instance()->measureOffsetY + PLScanner::instance()->measureOffsetY_S));
                            }
                        }
                        else
                        {
                            if (sp[i] > 50.0 || sp[i] <= 0.0)
                            {
                                nProfile.push_front(QPointF((sp.size() - 1 - i) * PLScanner::instance()->resolution, 0.0));

                            }
                            else
                            {
                                nProfile.push_front(QPointF((sp.size() - 1 - i) * PLScanner::instance()->resolution, sp[i] + PLScanner::instance()->measureOffsetY + PLScanner::instance()->measureOffsetY_S));
                            }
                        }
                    }
                }
                else
                {
                    OiWarning() << (tr("轮廓采集失败"));
                }


                if (PLScanner::instance()->debugging)
                {
                    _timeTick1 = QDateTime::currentDateTime().toMSecsSinceEpoch();
                    OiWarning() << "Profile loop Acquire:" << _timeTick1 - _timeTick2;
                    _timeTick2 = _timeTick1;
                }

                _mutex.lock();

                _profile = nProfile;
                _dir = dir;
                _success = true;

                if(_callback)
                {
                    _callback(nProfile, _data);
                }

                _mutex.unlock();

                if (PLScanner::instance()->debugging)
                {
                    _timeTick1 = QDateTime::currentDateTime().toMSecsSinceEpoch();
                    OiWarning() << "Profile loop callback:" << _timeTick1 - _timeTick2;
                    _timeTick2 = _timeTick1;
                }
            }

        }

        void AcquireProfileTask::quit()
        {
            //QMutexLocker locker(&_mutex);

            if (isRunning())
            {
                _impl->_sensor->abortDownload();

                _quit = true;

                wait();
            }
        }

        void AcquireProfileTask::start()
        {
            if (isRunning())
            {
                return;
            }

            QMutexLocker locker(&_mutex);
            _quit = false;
            _success = false;

            QThread::start();
        }

        void AcquireValueTask::setCallback(AcquireValueCallback callback, void* data)
        {
            QMutexLocker locker(&_mutex);
            _callback = callback;
            _data = data;
        }

        void AcquireValueTask::setParams(double pos /*= -1*/)
        {
            QMutexLocker locker(&_mutex);
            _pos = pos;
        }

        void AcquireValueTask::run()
        {
            if (!PLScanner::instance()->simulation)
            {
                Motor::instance()->locateMode();
                if (!Motor::instance()->isReady())
                {
                    OiShowMessage(tr("轴状态不正确"));
                    return;
                }

                if ((_impl->_sensor->getStatus() & Device::DS_Linked) == 0)
                {
                    OiShowMessage(tr("传感器未通信成功"));
                    return;
                }

                Motor::instance()->locatedRun(_pos);

                QThread::msleep(1000);

                OiShowMessage(tr("正在等待轴运动至定位点"));

                int timerCounter = 0;

                while (!Motor::instance()->locatedModeReady())
                {
                    if (_quit)
                    {
                        return;
                    }

                    if (timerCounter > 100)
                    {
                        OiShowMessage(tr("等待轴运动过程超时"));

                        return;
                    }

                    timerCounter++;

                    QThread::msleep(100);
                }
            }

            OiShowMessage(tr("正在定点测量"));

            while (!_quit)
            {
                double nvalue = 0.0;

                if (PLScanner::instance()->simulation)
                {
                    qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));

                    nvalue = 0.001 *(qrand() % 5000);
                }
                else
                {
                    _impl->_sensor->getValue(nvalue, 1000);

                    if (nvalue > 50.0 || nvalue < -50.0)
                    {
                        nvalue = 0.0;
                    }
                }

                _mutex.lock();

                _value = nvalue;
                _success = true;

                if (_callback)
                {
                    _callback(_value, _data);
                }

                _mutex.unlock();

                QThread::msleep(_loopTime/*PLScanner::instance()->pointMeasureInterval * 1000*/);
            }
           
        }

        void AcquireValueTask::quit()
        {
            if (isRunning())
            {
                _quit = true;
                wait();
            }
        }

        void AcquireValueTask::start()
        {
            if(isRunning())
            {
                return;
            }

            QMutexLocker locker(&_mutex);
            _quit = false;
            _success = false;

            QThread::start();
        }

        void SensorAcquireImpl::init()
        {
            OI_Q(SensorAcquire);

            if(!PLScanner::instance()->simulation)
            {
                //传感器初始化
            }

            q->connect(&profileTask, &QThread::started, q, &SensorAcquire::enterAcquire);
            q->connect(&profileTask, &QThread::finished, q, &SensorAcquire::leaveAcquire);
            q->connect(&profileTask, &QThread::finished, q, &SensorAcquire::onLeaveAcquire);

            q->connect(&valueTask, &QThread::started, q, &SensorAcquire::enterAcquire);
            q->connect(&valueTask, &QThread::finished, q, &SensorAcquire::leaveAcquire);
            q->connect(&valueTask, &QThread::finished, q, &SensorAcquire::onLeaveAcquire);

            _sensor = new OptexSensorControl();
            _sensor->init();

            profileTask._impl = this;
            valueTask._impl = this;
        }

        void SensorAcquireImpl::exit()
        {
            profileTask.quit();
            valueTask.quit();

            _sensor->exit();
            //传感器资源释放
            //...
        }

        SensorAcquire::SensorAcquire()
        {
            OI_I(SensorAcquire);
        }

        SensorAcquire::~SensorAcquire()
        {
            OI_E(SensorAcquire);
        }

        void SensorAcquire::init()
        {
            OI_IMPL()->init();
        }

        void SensorAcquire::exit()
        {
            OI_IMPL()->exit();
        }

        bool SensorAcquire::isWorking()
        {
            OI_F(SensorAcquire);
            return d->profileTask.isRunning() || d->valueTask.isRunning();
        }

        bool SensorAcquire::acquire(AcquireProfileCallback callback, void* data, OiProfile& retValue, bool& direction, double vel, double from /*= -1.0*/, double end /*= -1.0*/, bool blocking /*= false*/, int timeout /*= -1*/)
        {
            OI_F(SensorAcquire);
            if (PLScanner::instance()->simulation)
            {
                return true;
            }

            if (isWorking())
            {
                OiWarning() << (tr("正在采集.."));
                return false;
            }

            d->profileTask.setCallback(callback, data);
            d->profileTask.setParams(vel, from, end);
            d->profileTask.start();

            if (blocking)
            {
                int t1 = QDateTime::currentDateTime().toTime_t();
                int loopCount = 0;
                while(d->profileTask.isRunning() && loopCount < timeout / 100)
                {
                    QEventLoop loop;
                    QTimer::singleShot(100, &loop, SLOT(quit()));
                    loop.exec();

                    loopCount++;
                }

                if(loopCount >= timeout / 100)
                {
                    int t2 = QDateTime::currentDateTime().toTime_t();

                    PLScannerError::instance()->reportError(PLScannerError::ERR_CAPTURE_TIMEOUT);

                    d->profileTask.quit();

                    OiWarning() << "采集超时: timeout=" << t2 - t1;

                    return false;
                }
                else
                {
                    PLScannerError::instance()->clearError(PLScannerError::ERR_CAPTURE_TIMEOUT);

                    if(d->profileTask._success)
                    {
                        retValue = d->profileTask._profile;
                        direction = d->profileTask._dir;
                    }

                    return d->profileTask._success;
                }
            }
            else
            {
                return true;
            }
        }

        bool SensorAcquire::acquire(AcquireValueCallback callback, void* data, double& retValue, double pos /*= -1.0*/, bool blocking /*= true*/, int looptime/* = 100*/, int timeout /*= -1*/)
        {
            OI_F(SensorAcquire);

            if(isWorking())
            {
                return false;
            }

            d->valueTask.setCallback(callback, data);
            d->valueTask.setParams(pos);
            d->valueTask._loopTime = looptime;
            d->valueTask.start();

            if(blocking)
            {
                int loopCount = 0;
                bool success = false;

                while(!success)
                {
                    QEventLoop loop;
                    QTimer::singleShot(100, &loop, SLOT(quit()));
                    loop.exec();

                    loopCount++;

                    if (loopCount >= timeout / 100)
                    {
                        break;
                    }

                    d->valueTask._mutex.lock();
                    success = d->valueTask._success;
                    d->valueTask._mutex.unlock();
                }

                if(loopCount >= timeout / 100)
                {
                    PLScannerError::instance()->reportError(PLScannerError::ERR_CAPTURE_TIMEOUT);

                    d->valueTask.quit();

                    return false;
                }
                else
                {
                    PLScannerError::instance()->clearError(PLScannerError::ERR_CAPTURE_TIMEOUT);

                    retValue = d->valueTask._value;

                    d->valueTask.quit();

                    return true;
                }
            }
            else
            {
                return true;
            }
        }

        bool SensorAcquire::acquire(const QString file, OiProfile& retValue)
        {
            OI_F(SensorAcquire);

            retValue.clear();
            std::vector<double> sp;
            if (d->_sensor->loadFile(file, sp))
            {
                for (int i = 0; i < sp.size(); i++)
                {
                    if (sp[i] > 50.0 || sp[i] <= 0.0)
                    {
                        retValue.push_back(QPointF(i * PLScanner::instance()->resolution, 0.0));
                    }
                    else
                    {
                        retValue.push_back(QPointF(i * PLScanner::instance()->resolution, sp[i] + PLScanner::instance()->measureOffsetY + PLScanner::instance()->measureOffsetY_S));
                    }
                }
            }

            return true;
        }

        bool SensorAcquire::readTemperature(double & value1, double & value2)
        {
            OI_F(SensorAcquire);
            d->_sensor->getTemperature2(value2);
            d->_sensor->getTemperature1(value1);
            if ((value1 > 100 || value1 < 0) && (value2 > 0 && value2 < 100))
            {
                value1 = value2 + 2;
            }
            return true;
        }

        void SensorAcquire::abort()
        {
            OI_F(SensorAcquire);

            d->profileTask.quit();
            d->valueTask.quit();
        }

        void SensorAcquire::onLeaveAcquire()
        {
            OI_F(SensorAcquire);
            auto sendThread = sender();

            if (sendThread == &d->profileTask)
            {
                d->profileTask._quit = true;
                d->profileTask._callback = nullptr;
            }
            else
            {
                d->valueTask._quit = true;
                d->valueTask._callback = nullptr;
            }

            OiShowMessage(tr("已停止采集"));

            d->_sensor->stopCapture(10);
        }

        SensorAcquire* SensorAcquire::OiAcquire()
        {
            static SensorAcquire acquire;
            return &acquire;
        }

    }
}